package com.heima.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.mapper.UserMapper;
import com.heima.model.behavior.pojos.LikesBehavior;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.constants.BehaviorConstants;
import com.heima.model.user.dtos.UserLoginDto;
import com.heima.model.user.dtos.UserRelationDto;
import com.heima.model.user.pojos.User;
import com.heima.model.user.pojos.UserRelation;
import com.heima.service.UserService;
import com.heima.utils.UserThreadLocal;
import com.heima.utils.common.HutoolJWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.UUID;

/**
 * @author chenshan
 * @description 针对表【ap_user(APP用户信息表)】的数据库操作Service实现
 * @createDate 2022-10-14 09:50:37
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public ResponseResult loginAuth(UserLoginDto loginDto) {
        // 校验数据的合法性  手机号码
        if (StrUtil.isNotBlank(loginDto.getPhone()) && !PhoneUtil.isMobile(loginDto.getPhone())) {
            // 返回手机号码不合法
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "手机号码格式错误");
        }

        // 判断手机号码和密码是否合法
        if (StrUtil.isNotBlank(loginDto.getPhone())) {
            User user = getOne(Wrappers.lambdaQuery(User.class).eq(User::getPhone, loginDto.getPhone()));
            if (ObjectUtil.isNotNull(user)) {
                // 正常的登录逻辑
                // 拿到用户输入的密码 和 盐做MD5
                String pass = SecureUtil.md5(loginDto.getPassword() + user.getSalt());
                // 和数据库中的密码做对比
                if (!StrUtil.equals(pass, user.getPassword())) {
                    return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
                }
                // 判断账号是否被禁用
                if (user.getStatus() != 0) {
                    return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_STATUS_ERROR);
                }
                // 生成Token 并 返回
                HashMap<String, Object> mm = new HashMap<>();
                mm.put("id", user.getId());
                String token = HutoolJWT.createToken(mm);
                HashMap<String, Object> hashMap = new HashMap<>();
                hashMap.put("token", token);
                return ResponseResult.okResult(hashMap);
                // return ResponseResult.okResult(token);
            } else {
                // 自动注册
                // 把用户的信息保存到数据库中
                user = new User();
                user.setPhone(loginDto.getPhone());
                // 生成一个随机串 作为用户的盐
                String salt = UUID.randomUUID().toString().replace("-", "");
                user.setPassword(SecureUtil.md5(loginDto.getPassword() + salt));
                user.setSalt(salt);

                // 默认新创建的账号都是启用状态
                user.setStatus(0);
                user.setCreatedTime(DateTime.now());
                /* 保存数据到数据库中  相当于实现了用户的注册功能 */
                save(user);
            }

            // 游客登录
            // 生成Token 并 返回
            HashMap<String, Object> map = new HashMap<>();
            map.put("id", "");
            String token = HutoolJWT.createToken(map);

            HashMap<String, Object> hashMap = new HashMap<>();
            hashMap.put("token", token);
            return ResponseResult.okResult(hashMap);
            // return ResponseResult.okResult(token);
        }


        return null;
    }

    @Override
    public Integer selectUserId() {
        Integer userId = UserThreadLocal.get();
        if (ObjectUtil.isEmpty(userId)) {
            return null;
        }

        return userId;
    }

    /**
     * 用户行为 - 关注与取消关注
     * @param relationDto 用户关注行为
     * @return ResponseResult
     */
    @Override
    public ResponseResult userFollow(UserRelationDto relationDto) {
        // 校验参数的合法性
        if (!ObjectUtil.isAllNotEmpty(relationDto.getArticleId(), relationDto.getAuthorId(), relationDto.getOperation())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 接收用户id 和作者id
        Integer userId = UserThreadLocal.get();
        Integer authorId = relationDto.getAuthorId();
        if (ObjectUtil.isEmpty(userId)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        // 用户给作者点了关注
        if (relationDto.getOperation() == 0) {
            // 1.直接添加关注(以关注时间作为分数 有无分数作为是否关注的标记)
            redisTemplate.opsForZSet().add(BehaviorConstants.RELATION + userId, BehaviorConstants.FOLLOW + authorId, System.currentTimeMillis());
            redisTemplate.opsForZSet().add(BehaviorConstants.RELATION + authorId, BehaviorConstants.FANS + userId, System.currentTimeMillis());

            // 2.判断MongoDB中是否有关注记录
            UserRelation userRelation = mongoTemplate.findOne(Query.query(Criteria.where("userId").is(userId).and("authorId").is(authorId)), UserRelation.class);

            // 3.MongoDB中存在关注记录表示已关注 直接返回
            if (ObjectUtil.isNotEmpty(userRelation)) {
                return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
            }
            mongoTemplate.insert(UserRelation.builder().userId(userId).articleId(relationDto.getArticleId()).operation(0).authorId(relationDto.getAuthorId()).build());
        } else {
            // 用户取消关注啦
            redisTemplate.opsForZSet().remove(BehaviorConstants.RELATION + userId,
                    BehaviorConstants.FOLLOW + authorId);
            redisTemplate.opsForZSet().remove(BehaviorConstants.RELATION + authorId,
                    BehaviorConstants.FANS + userId);
            mongoTemplate.remove(Query.query(Criteria.where("userId").is(userId).and("authorId").is(authorId)), UserRelation.class);

        }

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}




